package cn.limitless.cathatmusic.filter;

import cn.limitless.cathatmusic.config.SecurityConfig;
import cn.limitless.cathatmusic.entity.User;
import cn.limitless.cathatmusic.service.UserService;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * <img src="http://blog.GnaixEuy.cn/wp-content/uploads/2021/08/bug.jpeg"/>
 *
 * @author GnaixEuy
 * @date 2022/1/26
 * @see <a href='https://github.com/GnaixEuy'> GnaixEuy的GitHub </a>
 */
public class JwtAuthorizationFilter extends BasicAuthenticationFilter {

	private final UserService userService;

	public JwtAuthorizationFilter(AuthenticationManager authenticationManager, UserService userService) {
		super(authenticationManager);
		this.userService = userService;
	}

	@Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
		String header = request.getHeader(SecurityConfig.HEADER_STRING);
		if (header == null || !header.startsWith(SecurityConfig.TOKEN_PREFIX)) {
			chain.doFilter(request, response);
			return;
		}
		UsernamePasswordAuthenticationToken authenticationToken = getAuthentication(header);
		SecurityContextHolder.getContext().setAuthentication(authenticationToken);
		chain.doFilter(request, response);
	}

	private UsernamePasswordAuthenticationToken getAuthentication(String header) {
		if (header != null) {
			String username = JWT.require(Algorithm.HMAC512(SecurityConfig.SECRET.getBytes()))
					.build()
					.verify(header.replace(SecurityConfig.TOKEN_PREFIX, ""))
					.getSubject();

			if (username != null) {
				final User user = this.userService.loadUserByUsername(username);
				return new UsernamePasswordAuthenticationToken(username, null, user.getAuthorities());
			}
		}
		return null;
	}
}
